/**
 * Copyright (c) 2010 Simple Graph Tools contributors. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 *
 * $Id$
 */

package org.sgt.datamodel.util;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EParameter;
import org.sgt.datamodel.Action;
import org.sgt.datamodel.ActionParameter;
import org.sgt.datamodel.ActionParameterKind;
import org.sgt.datamodel.ActionSpecification;
import org.sgt.datamodel.CreateSpecification;
import org.sgt.datamodel.DataStore;
import org.sgt.datamodel.DatamodelFactory;
import org.sgt.datamodel.DeleteSpecification;
import org.sgt.datamodel.Executor;
import org.sgt.datamodel.MultiPrimitive;
import org.sgt.datamodel.MultiReference;
import org.sgt.datamodel.Primitive;
import org.sgt.datamodel.QuerySpecification;
import org.sgt.datamodel.Reference;
import org.sgt.datamodel.UpdateSpecification;
import org.sgt.datamodel.Value;

/**
 * Behavioral Class for {@link Action}.
 * @author BUTTIGHOFFER-A
 *
 */
public class ActionHelper {
	
	/**
	 * Builds an {@link Action} content from its {@link ActionSpecification}
	 * (if defined). Nothing is done if {@link Action#getSpecification()} is null.
	 * @param action the {@link Action} to be built.
	 */
	public static final void buildFromSpecification(Action action){
		if (action != null && action.getSpecification() != null){

			ActionSpecification actSpec = action.getSpecification();
			
			EList<ActionParameter> paramsSpec = getParameters(actSpec);
			
			for (ActionParameter paramSpec : paramsSpec){
				String key = paramSpec.getName();
				Value value = buildValueFromSpec(paramSpec);
				value.setName(action.getName() + value.getName());
				switch (paramSpec.getKind().getValue()){
					case ActionParameterKind.INPUT_VALUE : action.getInputs().put(key, value); break;
					case ActionParameterKind.OUTPUT_VALUE : action.getOutputs().put(key, value); break;
					default : action.getParameters().put(key, value); 
				}
			}
		}
	}

	public static final Value buildValueFromSpec(ActionParameter paramSpec){
		Value value = null;
		EClassifier classifier = paramSpec.getEType();
		StringBuffer buff = new StringBuffer();
		buff.append("_");
		buff.append(paramSpec.getName());
		String key = buff.toString();
		if (classifier instanceof EClass) {
			if (paramSpec.isMany()) {
				value = DatamodelFactory.eINSTANCE.createMultiReference();
				((MultiReference) value).setType((EClass) classifier);
			} else {
				value = DatamodelFactory.eINSTANCE.createReference();
				((Reference) value).setType((EClass) classifier);
			}
			value.setName(key);
		} else if (classifier instanceof EDataType) {
			EDataType dataType = (EDataType) classifier;
			if (paramSpec.isMany()) {
				value = DatamodelFactory.eINSTANCE.createMultiPrimitive();
				((MultiPrimitive) value).setType(dataType);
			} else {
				value = DatamodelFactory.eINSTANCE.createPrimitive();
				((Primitive) value).setType(dataType);
			}
			value.setName(key);
		}
		return value;
	}
	
	public static final EList<ActionParameter> getParameters(ActionSpecification actionSpec){
		if (actionSpec == null) return null;
		EList<ActionParameter> parameters = new BasicEList<ActionParameter>();
		for (EParameter eParam : actionSpec.getEParameters()){
			if (eParam instanceof ActionParameter){
				parameters.add((ActionParameter) eParam);
			}
		}
		return parameters;
	}
	
	public static final void execute(Action action) throws ExecutionException {
		if (action == null || action.getDataStore() == null) return;
		DataStore dataStore = action.getDataStore();
		if (action.getExecutor() == null){
			// No executor specified.
			if (action.getSpecification() == null){
				// We have not defined what to do...
				ExecutionException execEx = new ExecutionException("No executor nor specification defined");
				throw execEx;
			} else {
				ActionSpecification actionSpec = action.getSpecification();
				if (actionSpec instanceof CreateSpecification){
					CreateActionExecutor.executeCreateAction(action, dataStore);
				}
				if (actionSpec instanceof UpdateSpecification){
					// We do not handle this yet...
					ExecutionException execEx = new ExecutionException("Not yet implemented");
					throw execEx;
				}
				if (actionSpec instanceof QuerySpecification){
					// We do not handle this yet...
					ExecutionException execEx = new ExecutionException("Not yet implemented");
					throw execEx;
				}
				if (actionSpec instanceof DeleteSpecification){
						// We do not handle this yet...
						ExecutionException execEx = new ExecutionException("Not yet implemented");
						throw execEx;
				}
				
			}
		} else {
			// We have an executor let's delegate to it ...
			Executor executor = action.getExecutor();
			executor.execute();
			
		}
	}
}
